/* Copyright (c) 2024 Qualcomm Technologies International, Ltd. */
/* %%version */

#include "csr_bt_cm_lib.h"

#include "gatt_ots_client_private.h"
#include "gatt_ots_client_common_util.h"
#include "gatt_ots_client_read_object.h"
#include "gatt_ots_client_select_object.h"
#include "gatt_ots_client_abort.h"
#include "service_handle.h"

GattOtsClient *otsClientMain;

GattOtscResultCode OtscGetResultCodeFromGattStatus(status_t status)
{
    GattOtscResultCode result;

    switch(status)
    {
        case CSR_BT_GATT_RESULT_SUCCESS:
            result = GATT_OTSC_RESULT_CODE_SUCCESS;
            break;

        case CSR_BT_GATT_RESULT_TRUNCATED_DATA:
            result = GATT_OTSC_RESULT_CODE_TRUNCATED_DATA;
            break;

        default:
            result = GATT_OTSC_RESULT_CODE_OPERATION_FAILED;
            break;
    }
    return (result);
}

ServiceHandle GattOtscGetServiceHandle(GOTSC **gattOtsClient, CsrCmnList_t *list)
{
    ServiceHandleListElm_t *elem = OTSC_ADD_SERVICE_HANDLE(*list);

    elem->service_handle = ServiceHandleNewInstance((void **) gattOtsClient, sizeof(GOTSC));

    if (*gattOtsClient)
    {
        (*gattOtsClient)->srvcElem = elem;
    }

    return (elem->service_handle);
}

void GattOtscInitServiceHandleList(CsrCmnListElm_t *elem)
{
    ServiceHandleListElm_t *cElem = (ServiceHandleListElm_t *) elem;

    cElem->service_handle = 0;
}

GattOtscDeviceData *GattOtscGetDeviceDataReq(ServiceHandle clntHndl)
{
    GOTSC *gattOtsClient = ServiceHandleGetInstanceData(clntHndl);

    if (gattOtsClient)
    {
        GattOtscDeviceData *deviceData = CsrPmemZalloc(sizeof(GattOtscDeviceData));

        memcpy(deviceData, &(gattOtsClient->deviceData), sizeof(GattOtscDeviceData));

        return (deviceData);
    }

    return NULL;
}

CsrBool OtscFindSrvcHndlByConnId(CsrCmnList_t *list, CsrBtConnId btConnId, GOTSC **gattOtsClient)
{
    ServiceHandleListElm_t *currentElem;

    for (currentElem = (ServiceHandleListElm_t *)list->first; currentElem; currentElem = currentElem->next)
    {
        ServiceHandle svcHandle = currentElem->service_handle;
        GOTSC *currOtsClient    = ServiceHandleGetInstanceData(svcHandle);

        if (currOtsClient && currOtsClient->btConnId == btConnId)
        {
            *gattOtsClient = currOtsClient;
            return (TRUE);
        }
    }

    return (FALSE);
}

ServiceHandle GattOtscGetCharacHandleForCharacId(GOTSC *const gattOtsClient,
                                                 GattOtscCharacteristicsId characId)
{
    ServiceHandle handle = INVALID_PROFILE_HANDLE;

    switch (characId)
    {
        case GATT_OTSC_CHARAC_ID_OTS_FEATURE:
        {
            if (gattOtsClient->deviceData.otsFeatureHandle)
            {
                handle = gattOtsClient->deviceData.otsFeatureHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_NAME:
        {
            if (gattOtsClient->deviceData.objNameHandle)
            {
                handle = gattOtsClient->deviceData.objNameHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_TYPE:
        {
            if (gattOtsClient->deviceData.objTypeHandle)
            {
                handle = gattOtsClient->deviceData.objTypeHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_SIZE:
        {
            if (gattOtsClient->deviceData.objSizeHandle)
            {
                handle = gattOtsClient->deviceData.objSizeHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_FIRST_CREATED:
        {
            if (gattOtsClient->deviceData.objFirstCreatedHandle)
            {
                handle = gattOtsClient->deviceData.objFirstCreatedHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_LAST_MODIFIED:
        {
            if (gattOtsClient->deviceData.objLastModifiedHandle)
            {
                handle = gattOtsClient->deviceData.objLastModifiedHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_ID:
        {
            if (gattOtsClient->deviceData.objIdHandle)
            {
                handle = gattOtsClient->deviceData.objIdHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_PROPERTIES:
        {
            if (gattOtsClient->deviceData.objPropertiesHandle)
            {
                handle = gattOtsClient->deviceData.objPropertiesHandle;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_LIST_FILTER:
        {
            if (gattOtsClient->deviceData.objListFilterHandle1)
            {
                handle = gattOtsClient->deviceData.objListFilterHandle1;
            }
            else if (gattOtsClient->deviceData.objListFilterHandle2)
            {
                handle = gattOtsClient->deviceData.objListFilterHandle2;
            }
            else if (gattOtsClient->deviceData.objListFilterHandle3)
            {
                handle = gattOtsClient->deviceData.objListFilterHandle3;
            }
            break;
        }
        case GATT_OTSC_CHARAC_ID_OBJ_CHANGED:
        {
            if (gattOtsClient->deviceData.objChangedHandle)
            {
                handle = gattOtsClient->deviceData.objChangedHandle;
            }
            break;
        }
        default:
        {
            GATT_OTS_CLIENT_ERROR("GOTSC: GattOtscGetCharacHandleForCharacId: Unknown characId !\n");
            break;
        }
    }

    return (handle);
}

GattOtscCharacteristicsId GattOtscGetCharacIdForCharacHandle(GOTSC *const gattOtsClient,
                                                             ServiceHandle handle)
{
    CsrUint16 characId = GATT_OTSC_CHARAC_ID_NONE;

    if (handle == gattOtsClient->deviceData.objNameHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_NAME;
    }
    else if (handle == gattOtsClient->deviceData.objTypeHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_TYPE;
    }
    else if (handle == gattOtsClient->deviceData.objSizeHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_SIZE;
    }
    else if (handle == gattOtsClient->deviceData.objFirstCreatedHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_FIRST_CREATED;
    }
    else if (handle == gattOtsClient->deviceData.objLastModifiedHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_LAST_MODIFIED;
    }
    else if (handle == gattOtsClient->deviceData.objIdHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_ID;
    }
    else if (handle == gattOtsClient->deviceData.objPropertiesHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_PROPERTIES;
    }
    else if (handle == gattOtsClient->deviceData.objListFilterHandle1 ||
             handle == gattOtsClient->deviceData.objListFilterHandle2 ||
             handle == gattOtsClient->deviceData.objListFilterHandle3)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_LIST_FILTER;
    }
    else if (handle == gattOtsClient->deviceData.objChangedHandle)
    {
        characId = GATT_OTSC_CHARAC_ID_OBJ_CHANGED;
    }
    else
    {
        /* Nothing to do */
    }

    return (characId);
}

GattOtscDeviceData* GattOtscGetHandlesReq(ServiceHandle svcHandle)
{
    GOTSC *gattOtsClient = ServiceHandleGetInstanceData(svcHandle);

    GATT_OTS_CLIENT_INFO("GOTSC: GattOtscGetHandlesReq: svcHandle[%0x]\n", svcHandle);

    if (gattOtsClient)
    {
        GattOtscDeviceData *otsHandles = CsrPmemZalloc(sizeof(GattOtscDeviceData));

        memcpy(otsHandles, &(gattOtsClient->deviceData), sizeof(GattOtscDeviceData));

        return (otsHandles);
    }

    return NULL;
}

static void oacpTimeOutHandler(uint16 val, GOTSC *const gattOtsClient)
{
    if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_READ_OBJ_CONTENT)
    {
        /* Send Read procedure's failure message to app */
        OtscSendReadObjectCfm(gattOtsClient, 0, NULL, FALSE,
                              GATT_OTSC_RESULT_CODE_TIMEOUT,
                              GATT_SUPPLIER_OTS_CLIENT);
    }
    else if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_ABORT_PROCEDURE)
    {
        /* Send abort procedure's failure message to app */
        OtscSendAbortCfm(gattOtsClient,
                         GATT_OTSC_RESULT_CODE_TIMEOUT,
                         GATT_SUPPLIER_OTS_CLIENT);

        if (gattOtsClient->btConnId != CSR_BT_CONN_ID_INVALID)
        {
            /* Disconnect the L2CAP connections */
            CsrBtCml2caDisconnectReqSend(gattOtsClient->btConnId);
        }
    }

    GATT_OTS_CLIENT_INFO("GOTSC: oacpTimeOutHandler: svcHandle(0x%02x)\n", gattOtsClient->srvcElem->service_handle);

    /*Reset the timer value */
    gattOtsClient->timerId = 0;
    CSR_UNUSED(val);
}

static void olcpTimeOutHandler(uint16 val, GOTSC *const gattOtsClient)
{
    if (gattOtsClient->pendingCmd & OTSC_PENDING_OP_OLCP_PROCEDURE)
    {
        /* Send OLCP procedure's failure message to app */
        OtscSendSelectObjectCfm(gattOtsClient,
                                GATT_OTSC_RESULT_CODE_TIMEOUT,
                                GATT_SUPPLIER_OTS_CLIENT);
    }

    if (gattOtsClient->btConnId != CSR_BT_CONN_ID_INVALID)
    {
        /* Disconnect the L2CAP connections */
        CsrBtCml2caDisconnectReqSend(gattOtsClient->btConnId);
    }

    GATT_OTS_CLIENT_INFO("GOTSC: olcpTimeOutHandler: svcHandle(0x%02x)\n", gattOtsClient->srvcElem->service_handle);

    gattOtsClient->timerId = 0;
    CSR_UNUSED(val);
}

void OtscStartOacpTimer(GOTSC *const gattOtsClient)
{
    /* Start OACP timer and wait for OACP control point indication */
    gattOtsClient->timerId = OTSC_START_OACP_TIMER(gattOtsClient);
}

void OtscStartOlcpTimer(GOTSC *const gattOtsClient)
{
    /* Start OLCP timer and wait for OLCP control point indication */
    gattOtsClient->timerId = OTSC_START_OLCP_TIMER(gattOtsClient);
}

